// (C) 2021 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`define SCM_PFR_MAX_ADDR  15 // define how many DW registers are used
//Define Address for each regiter
`define SCM_PFR_FPGA_VERSION_ADDR       16'h00
`define SCM_PFR_REV_CTRL_ADDR           16'h04
`define SCM_PFR_BUILD_TIME_ADDR         16'h08
`define SCM_PFR_BUILD_CATEGORY_ADDR     16'h0C
`define SCM_PFR_DEVICE_LOCATION_ADDR    16'h10
`define SCM_PFR_STATUS_ADDR             16'h14
`define SCM_PFR_CONTROL_ADDR            16'h18
`define SCM_PFR_SCRATCH_ADDR            16'h1C

//Define Default Value
`define SCM_PFR_MAJOR_RELEASE_NUM_DEF  16'h1
`define SCM_PFR_MINOR_RELEASE_NUM_DEF  16'h1

`define SCM_PFR_GIT_HASH_DEF           32'h1

`define SCM_PFR_BUILD_YEAR_DEF         04'h1
`define SCM_PFR_BUILD_MONTH_DEF        04'h1
`define SCM_PFR_BUILD_DAY_DEF          08'h1
`define SCM_PFR_BUILD_HOUR_DEF         08'h1
`define SCM_PFR_BUILD_MINUTE_DEF       08'h1

`define SCM_PFR_BUILD_CATEGORY_DEF     01'h0

`define SCM_PFR_DEVICE_LOCTAION_DEF    02'h1


module scm_pfr_csr 
(
    input             clk,
    input             reset,

    //avmm interface
    input      [31:0] avmm_address,
    input             avmm_write,
    input      [31:0] avmm_writedata,          
    input             avmm_read,     
    output reg [31:0] avmm_readdata,      
    output reg        avmm_readdatavalid, 
    output            avmm_waitrequest,           
    input      [ 3:0] avmm_byteenable
);

wire [15:0] addr_local; //Only 16 bits out of 32 bits avmm_address supported
reg  [31:0] scm_global_reg [`SCM_PFR_MAX_ADDR:0]; //local register
reg  [31:0] illegal_write;

assign avmm_waitrequest = 1'b0;

assign addr_local = avmm_address[15:0];

//read registers
always @ ( posedge clk ) begin
    if ( reset ) begin
        avmm_readdata <= 32'h0;
    end else begin
        if ( avmm_read && !( |avmm_address[31:16]) && (&avmm_byteenable)) begin
            case (addr_local)
                 `SCM_PFR_FPGA_VERSION_ADDR    : avmm_readdata <= {`SCM_PFR_MAJOR_RELEASE_NUM_DEF, `SCM_PFR_MINOR_RELEASE_NUM_DEF};
                 `SCM_PFR_REV_CTRL_ADDR        : avmm_readdata <= `SCM_PFR_GIT_HASH_DEF;
                 `SCM_PFR_BUILD_TIME_ADDR      : avmm_readdata <= {`SCM_PFR_BUILD_YEAR_DEF,
                                                                   `SCM_PFR_BUILD_MONTH_DEF,
                                                                   `SCM_PFR_BUILD_DAY_DEF,
                                                                   `SCM_PFR_BUILD_HOUR_DEF,
                                                                   `SCM_PFR_BUILD_MINUTE_DEF };
                 `SCM_PFR_BUILD_CATEGORY_ADDR  : avmm_readdata <= {31'h0, `SCM_PFR_BUILD_CATEGORY_DEF};
                 `SCM_PFR_DEVICE_LOCATION_ADDR : avmm_readdata <= {30'h0, `SCM_PFR_DEVICE_LOCTAION_DEF};
                 `SCM_PFR_STATUS_ADDR          : avmm_readdata <= {31'h0, 1'b1};
                 `SCM_PFR_CONTROL_ADDR         : avmm_readdata <= scm_global_reg[`SCM_PFR_CONTROL_ADDR / 4];
                 `SCM_PFR_SCRATCH_ADDR         : avmm_readdata <= scm_global_reg[`SCM_PFR_SCRATCH_ADDR / 4];   
                default                : avmm_readdata <= 32'h0BAD_0ADD; //reture bad addr
            endcase
        end
    end
end

always @ ( posedge clk ) begin
    if ( reset ) begin
        avmm_readdatavalid <= 1'b0;
    end else begin
        if ( avmm_read && (&avmm_byteenable)) begin
            avmm_readdatavalid <= 1'b1; //readvalid asserts one clock cycle after read assetted.
        end else begin
            avmm_readdatavalid <= 1'b0;
        end
    end
end

//write registers
always @ ( posedge clk ) begin
    if ( reset ) begin
        scm_global_reg[`SCM_PFR_CONTROL_ADDR/4] <= 32'h0;
        scm_global_reg[`SCM_PFR_SCRATCH_ADDR/4] <= 32'h0;
    end else begin
        if ( avmm_write && !( |avmm_address[31:16]) && (&avmm_byteenable)) begin
            case (addr_local)
                `SCM_PFR_CONTROL_ADDR    : scm_global_reg[`SCM_PFR_CONTROL_ADDR/4] <= avmm_writedata;
                `SCM_PFR_SCRATCH_ADDR    : scm_global_reg[`SCM_PFR_SCRATCH_ADDR/4] <= avmm_writedata;
                default          : illegal_write                   <= avmm_writedata; //reture bad addr
            endcase
        end
    end
end


endmodule    